package com.zj.utils;

import com.zj.binding.MapperRegistry;
import com.zj.dataSource.UnpooledDataSourceFactory;
import com.zj.exception.ZJBatisException;
import com.zj.executor.DefaultParameterHandler;
import com.zj.executor.Executor;
import com.zj.executor.ParameterHandler;
import com.zj.executor.SimpleExecutor;
import com.zj.mapping.MappedStatement;
import com.zj.sqlSession.SqlSession;
import com.zj.statement.PreparedStatementHandler;
import com.zj.statement.StatementHandler;
import com.zj.transaction.JdbcTransactionFactory;
import com.zj.transaction.ManagedTransactionFactory;
import com.zj.dataSource.PooledDataSourcFactory;
import com.zj.transaction.Transaction;

import java.util.*;

public class Configuration {
    protected Environment environment;
    //配置文件开头的properties文件中加载的属性都放入到variables变量中，在具体解析需要变量替换的时候用。
    protected Properties variables;
    protected MapperRegistry mapperRegistry = new MapperRegistry(this);
//    protected final InterceptorChain interceptorChain;
//    protected final TypeHandlerRegistry typeHandlerRegistry;
    protected final static  TypeAliasRegistry typeAliasRegistry=new TypeAliasRegistry();
    protected final Set<String> loadedResources = new HashSet<String>();
    protected final Map<String, MappedStatement> mappedStatements = new HashMap<>();


    static{
        typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
        typeAliasRegistry.registerAlias("POOLED", PooledDataSourcFactory.class);
        typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
    }



    public TypeAliasRegistry getTypeAliasRegistry() {
        return typeAliasRegistry;
    }

    public Environment getEnvironment() {
        return environment;
    }

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

//    public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject) {
//        ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject);
////        parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
//        return parameterHandler;
//    }

//    public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
//                                                ResultHandler resultHandler, BoundSql boundSql) {
//        ResultSetHandler resultSetHandler = mappedStatement.hasNestedResultMaps() ? new NestedResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql,
//                rowBounds) : new FastResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
//        resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
//        return resultSetHandler;
//    }

    public StatementHandler newStatementHandler(Executor executor, MappedStatement ms, Object parameterObject) {
        StatementHandler delegate;
        switch (ms.getStatementType()) {
            case PREPARED:
                delegate = new PreparedStatementHandler(executor, ms, parameterObject);
                break;
            default:
                throw new ZJBatisException("Unknown statement type: " + ms.getStatementType());
        }
//        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return delegate;
    }
    public Executor newExecutor(Transaction transaction) {
        Executor executor = new SimpleExecutor(this, transaction);

//        if (this.cacheEnabled) {
//            executor = new CachingExecutor((Executor)executor);
//        }

//        Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
        return executor;
    }

    public void addLoadedResource(String resource) {
        loadedResources.add(resource);
    }

    public boolean isResourceLoaded(String resource) {
        return loadedResources.contains(resource);
    }

    public void addMappedStatement(MappedStatement ms) {
        mappedStatements.put(ms.getId(), ms);
    }

    public <T> void addMapper(Class<T> type) {
        mapperRegistry.addMapper(type);
    }

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return mapperRegistry.getMapper(type, sqlSession);
    }

    public boolean hasMapper(Class<?> type) {
        return mapperRegistry.hasMapper(type);
    }

    public MappedStatement getMappedStatement(String id) {
        return mappedStatements.get(id);
    }



}
